package net.zoneland.knowledge.service.impl.search;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import net.zoneland.knowledge.utils.QaBankUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;

import net.zoneland.knowledge.cache.RedisCacheUtil;
import net.zoneland.knowledge.constant.BizConstant;
import net.zoneland.knowledge.constant.Constants;
import net.zoneland.knowledge.enums.DictParentEnum;
import net.zoneland.knowledge.enums.LevelEnum;
import net.zoneland.knowledge.enums.QueryTypeEnum;
import net.zoneland.knowledge.enums.TypeEnum;
import net.zoneland.knowledge.model.DataCategory;
import net.zoneland.knowledge.model.DictItem;
import net.zoneland.knowledge.model.EsQuestion;
import net.zoneland.knowledge.model.QaQueryDto;
import net.zoneland.knowledge.model.QaResponse;
import net.zoneland.knowledge.service.ApiService;
import net.zoneland.knowledge.service.DictItemService;
import net.zoneland.knowledge.service.QaBankService;
import net.zoneland.knowledge.service.QaQueryService;
import net.zoneland.knowledge.utils.ResponseUtils;

/**
 * 对查询查询进行处理.
 *
 * @author: bcc
 * 2021/5/26
 */
@Service("searchOperationImplDealResult")
public class SearchOperationImplDealResult extends AbstractSearchOperation {

    /**
     * logger.
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(SearchOperationImplDealResult.class);

    @Autowired
    private QaQueryService qaQueryService;

    @Autowired
    private RedisCacheUtil redisCache;

    @Autowired
    private QaBankService qaBankService;

    @Autowired
    private ApiService apiService;

    @Autowired
    private DictItemService dictItemService;

    @Override
    public boolean needRun(final SearchDto searchDto) {
        return !searchDto.isStopDeal();
    }

    @Override
    protected void doSearchOrDeal(final SearchDto searchDto) throws Exception {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("searchOperationImplDealResult");
        }
        if (null == searchDto.getQaResponse()) {
            List<EsQuestion> esQuestions = searchDto.getEsQuestions();
            //将查询结果组装成符合前端要求
            //这里只针对问答的场景
            if (CollectionUtils.isEmpty(esQuestions)) {
                QaResponse qaResponse = null;
                if ("我的收藏".equals(searchDto.getQaQueryDto().getQueryText())) {
                    final String noAnswer = dictItemService.findDictByParentId(DictParentEnum.NO_ANSWER_REPLY.getValue()).stream().
                        filter(dictItem -> Constants.NO_ANSWER_KEY_FAVORITE.equals(dictItem.getDictValue())).map(
                        DictItem::getDictName).findFirst().orElse(null);
                    qaResponse = ResponseUtils.generateNoAnswerForFavorite(noAnswer);
                } else {
                    final String noAnswer = dictItemService.findDictByParentId(DictParentEnum.NO_ANSWER_REPLY.getValue()).stream().
                        filter(dictItem -> Constants.NO_ANSWER_KEY_ANSWER.equals(dictItem.getDictValue())).map(
                        DictItem::getDictName).findFirst().orElse(null);
                    qaResponse = ResponseUtils.generateNoAnswer(searchDto.getQaQueryDto().getRobotName(), noAnswer);
                }
                searchDto.setQaResponse(qaResponse);
                return;
            }
            checkFavorite(searchDto.getQaQueryDto().getLoginUserPojo().getUserID(), esQuestions);
            qaQueryService.setRobotName(esQuestions, searchDto.getQaQueryDto());
            searchDto.setLeve1Title(esQuestions.stream()
                .map(EsQuestion::getLevel1Title).distinct()
                .collect(Collectors.joining(",")));
            if (CollectionUtils.isEmpty(searchDto.getQaQueryDto().getWordTokens())) {
                searchDto.getQaQueryDto().setWordTokens(Lists.newArrayList(searchDto.getQaQueryDto().getQueryText()));
            }
            final List<EsQuestion> esQuestionList = esQuestions.stream()
                    .filter(esQuestion -> QaBankUtils.checkQaBankToFilter(getStringIdsForList(esQuestion.getUserIds()),
                            getStringIdsForList(esQuestion.getDeptIds()), esQuestion.getCategory(),
                            esQuestion.getLevel1Title(), searchDto.getQaQueryDto().getLoginUserPojo()))
                    .collect(Collectors.toList());
            if (esQuestionList.size() == 1 && searchDto.getQaQueryDto().getQaType() != QueryTypeEnum.QUERY_BY_PATH) {
                final EsQuestion esQuestion = esQuestionList.get(0);
                qaBankService.loadMoreInfoFromDb(esQuestion, searchDto.getQaQueryDto().getVisitType());
                QaResponse qaResponse = ResponseUtils.assembleResponse(esQuestion, searchDto.getQaQueryDto());
                searchDto.setQaResponse(qaResponse);
            } else {
                //** 多个结果，把答案清空，防止返回结果太大
                if(esQuestionList.size() > 1) {
                    for (EsQuestion esQuestion : esQuestionList) {
                        esQuestion.setAnswer(null);
                    }
                }
                //多条记录，多个结果要合并
                QaResponse qaResponse = assembleResponseV2(esQuestionList, searchDto.getQaQueryDto());
                searchDto.setQaResponse(qaResponse);
            }
        }
    }

    /**
     * 将id集合转成String
     * @param ids
     * @return
     */
    private String getStringIdsForList(final List<String> ids){
        return Optional.ofNullable(ids)
                .map(list -> list.stream().collect(Collectors.joining(Constants.STRING_SEMICOLON)))
                .orElse(null);
    }

    /**
     * 返回list的场景只要返回题库对象就行了
     * @param esQuestions
     * @param qaQueryDto
     * @return
     */
    private QaResponse assembleResponseV2(final List<EsQuestion> esQuestions, final QaQueryDto qaQueryDto) {
        QaResponse qaResponse = new QaResponse();
        qaResponse.setType(TypeEnum.LIST.getValue());
        List<Map<String, Object>> list = new ArrayList<>();
        for(EsQuestion esQuestion: esQuestions) {
            Map<String, Object> map = ResponseUtils.transferEsQuestion(esQuestion, qaQueryDto);
            list.add(map);
        }
        qaResponse.setData(list);
        qaResponse.setWordTokens(qaQueryDto.getWordTokens());
        return qaResponse;
    }

    /**
     * 设置收藏.
     * @param userId 用户id
     * @param esQuestions 题库集合
     */
    public void checkFavorite(final String userId, final List<EsQuestion> esQuestions) {
        final Set<Object> esIds = redisCache.sget(BizConstant.FAVORITE_CATE + userId);
        if (CollectionUtils.isNotEmpty(esIds) && CollectionUtils.isNotEmpty(esQuestions)) {
            esQuestions.stream().forEach(item -> {
                if (esIds.contains(item.getId())) {
                    item.setFavorite(true);
                }
            });
        }
    }

    /**
     * 多个结果返回时.
     * 按查询场景拼装参数
     * search返回结果从第一级开始返回
     * queryByPath从最后匹配那一级返回
     * @param esQuestions 题库集合
     * @param qaQueryDto 查询参数
     * @return 结果
     */
    private QaResponse assembleResponse(final List<EsQuestion> esQuestions, final QaQueryDto qaQueryDto) {
        QaResponse qaResponse = new QaResponse();
        qaResponse.setType(TypeEnum.LIST.getValue());
        LevelEnum rootLevel = LevelEnum.LEVEL1;
        if (qaQueryDto.getQaType() == QueryTypeEnum.QUERY_BY_PATH) {
            if (StringUtils.isNotBlank(qaQueryDto.getLevel3Title())) {
                rootLevel = LevelEnum.LEVEL3;
            } else if (StringUtils.isNotBlank(qaQueryDto.getLevel2Title())){
                rootLevel = LevelEnum.LEVEL2;
            }
        }
        final List<DataCategory> dataCategories = apiService.getDataCategory();
        //返回数据规则
        //分类返回结果带顺序，按后台数据分类顺序
        //相同父科目的数据要归到一起
        //科目包含关键字的问答优先级比较高
        Map<String, List<EsQuestion>> dataMap = new HashMap<>();
        //防止重复科目
        Map<String, Set<String>> recordMap = new HashMap<>();
        for (EsQuestion esQuestion : esQuestions) {
            List<EsQuestion> categoryResultList = dataMap.get(esQuestion.getCategory());
            Set<String> levels = recordMap.get(esQuestion.getCategory());
            if (null == categoryResultList) {
                categoryResultList = new ArrayList<>();
            }
            if (null == levels) {
                levels = new HashSet<>();
            }
            // 判断比较的科目
            String levelTitle = rootLevel.getTitle(esQuestion);
            if (!levels.contains(levelTitle)) {
                levels.add(levelTitle);
                categoryResultList.add(esQuestion);
                dataMap.put(esQuestion.getCategory(), categoryResultList);
                recordMap.put(esQuestion.getCategory(), levels);
            }
        }
        List<Map<String, Object>> list = new ArrayList<>();
        for (DataCategory category : dataCategories) {
            List<EsQuestion> categoryResultList = dataMap.get(category.getKey());
            if (null != categoryResultList) {
                List<Map<String, Object>> list1 = ResponseUtils.generateResponse(categoryResultList, qaQueryDto, rootLevel);
                list.addAll(list1);
            }
        }
        qaResponse.setData(list);
        qaResponse.setWordTokens(qaQueryDto.getWordTokens());
        return qaResponse;
    }

}
